import Watcher from "./watcher.js";
export default class Compile {
  constructor(el, vm) {
    this.vm = vm;
    this.el = el;
    this.fragment = null;
    this.init();
  }
  init() {
    this.el = this.isElementNode(this.el)
      ? this.el
      : document.querySelector(this.el);
    this.fragment = this.node2fragment(this.el);
    this.compile(this.fragment);
    this.el.appendChild(this.fragment);
  }
  // 生成dom片段
  node2fragment(el) {
    let fragment = document.createDocumentFragment();
    let child = el.firstChild;
    while (child) {
      fragment.appendChild(child);
      child = el.firstChild;
    }
    return fragment;
  }
  // 编译
  compile(fragment) {
    let childNode = fragment.childNodes;
    const reg = /\{\{(.*)\}\}/;
    Array.from(childNode).forEach(child => {
      const text = child.textContent;
      if (this.isElementNode(child)) {
        // 元素节点
        this.compileElement(child);
      } else if (this.isTextNode(child) && reg.test(text)) {
        // 文本节点
        this.compileText(child, reg.exec(text)[1]);
      }
      if (child.childNodes && child.childNodes.length) {
        this.compile(child);
      }
    });
  }
  // 编译元素节点
  compileElement(node) {
    const attrs = node.attributes;
    Array.from(attrs).forEach(attr => {
      let dir = attr.name;
      // 是否为指令
      if (this.isDirective(dir)) {
        const exp = attr.value;
        dir = dir.substring(2);
        // 事件指令
        if (this.isDirEvent(dir)) {
          this.compileEvent(node, dir, exp);
        }
        // v-model指令
        if (this.isDirModel(dir)) {
          this.compileModel(node, dir, exp);
        }
        // ...
        node.removeAttribute(attr.name);
      }
    });
  }
  // 编译文本节点
  compileText(node, exp) {
    const initText = this.vm[exp];
    // 初始化文本节点
    this.updaterText(node, initText);
    // 监听数据变化,更新文本节点
    new Watcher(this.vm, exp, value => {
      this.updaterText(node, value);
    });
  }
  // 编译事件
  compileEvent(node, dir, exp) {
    const eventType = dir.split(":")[1];
    const fn = this.vm.$options.methods && this.vm.$options.methods[exp];
    if (!eventType || !fn) return;
    node.addEventListener(eventType, fn.bind(this.vm), false);
  }
  // 编译v-model
  compileModel(node, dir, exp) {
    let value = this.vm[exp];
    this.updateModel(node, value);
    node.addEventListener("input", e => {
      let newVal = e.target.value;
      if (value === newVal) return;
      value = newVal;
      this.vm[exp] = value;
    });
  }
  // 更新文本节点
  updaterText(node, value) {
    node.textContent = typeof value === "undefined" ? "" : value;
  }
  // 更新v-model节点
  updateModel(node, value) {
    node.value = typeof value === "undefined" ? "" : value;
  }
  // 判断指令 事件 元素 文本
  isDirective(dir) {
    return dir.indexOf("v-") === 0;
  }
  isDirModel(dir) {
    return dir.indexOf("model") === 0;
  }
  isDirEvent(dir) {
    return dir.indexOf("on:") === 0;
  }
  isElementNode(node) {
    return node.nodeType === 1;
  }
  isTextNode(node) {
    return node.nodeType === 3;
  }
}
